// SE-Download.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#define TRUE 1
#define FALSE 0
#define NOFILE 2
#define SECONDS_IN_A_DAY 86400

struct cc_temp {
	char stuff[141];
	char watts1[5];
	char stuff_1[26];
	char watts2[5];
	char stuff_2[21];
};


static int receive_count = 0;
static int watts_5_min_interval_count = 0;
static int watts_5_min_average;
static int watts_sub_total = 0;
static int in_session = FALSE;
static FILE *fpLog;

static char api_key[80];
static char system_id[80];
static char plant_name[80];
static char se_executable[MAX_PATH];
static char se_path[MAX_PATH];
static char se_input_path[MAX_PATH];
static char se_output_path[MAX_PATH];
static FILE *fpcc;
static char s_time_out[80];
static char se_password[80];

static char init_file_name[] = "se-download.ini";
static FILE *pfinit;

static	HANDLE phNewTimer = NULL;
static	DWORD time_out = 180000;
static	DWORD Period = 0;
static	ULONG Flags = WT_EXECUTEDEFAULT;
static	BOOL timer_status = 0;
static	HANDLE TimerQueue = NULL;
static	PVOID Parameter = 0;
static int g_timer_status = TRUE;
static int g_process_killed = FALSE;
/*static int sundown = FALSE;*/
static int previous_days_to_generate = 0;


static char my_lat[80];
static char my_long[80];
static char my_tz[80];



double pi = 3.14159;
double degs;
double rads;

double L,g,daylen;
double SunDia = 0.53;     // Sunradius degrees
double AirRefr = 34.0/60.0; // athmospheric refraction degrees //

void print_time(void)
{
	time_t time_now;
	struct tm *now;
	char *my_time;
	char s_my_time[80];
	int size;

	time_now=time(&time_now);
	now=localtime(&time_now);
	my_time = asctime(now);
	size = strlen(my_time);
	my_time[size - 1] = '\0';
	strcpy(s_my_time,my_time);
	fprintf(fpLog,"%s: ",s_my_time);
}




int init_params()
{
	char buffer[MAX_PATH];
	char *token;
	int return_status = TRUE;
	int compare_status = FALSE;

	pfinit = fopen(init_file_name,"r");
	if (pfinit == NULL)
	{
		perror("Error Opening Init File\n");
		return FALSE;
	}

	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(se_executable,token);
	}else{
		return_status = FALSE;
	}
	
	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(se_path,token);
	}else{
		return_status = FALSE;
	}

	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(se_password,token);
	}else{
		return_status = FALSE;
	}
	

	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(plant_name,token);
	}else{
		return_status = FALSE;
	}

	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(se_input_path,token);
	}else{
		return_status = FALSE;
	}
	
	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(se_output_path,token);
	}else{
		return_status = FALSE;
	}
	
	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(s_time_out,token);
	}else{
		return_status = FALSE;
	}
	
	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(my_lat,token);
	}else{
		return_status = FALSE;
	}
	

	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(my_long,token);
	}else{
		return_status = FALSE;
	}
	
	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		strcpy(my_tz,token);
	}else{
		return_status = FALSE;
	}

	fgets(buffer,sizeof (buffer),pfinit);
	token = strtok(buffer,";");
	if(token != NULL){
		previous_days_to_generate = atoi(token);
	}else{
		return_status = FALSE;
	}
	
	fclose(pfinit);
	return return_status;
}

//   Get the days to J2000
//   h is UT in decimal hours
//   FNday only works between 1901 to 2099 - see Meeus chapter 7

double FNday (int y, int m, int d, float h) {
long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
// type casting necessary on PC DOS and TClite to avoid overflow
luku+= (long int)y*367;
return (double)luku - 730531.5 + h/24.0;
};

//   the function below returns an angle in the range
//   0 to 2*pi

double FNrange (double x) {
    double b = 0.5*x / pi;
    double a = 2.0*pi * (b - (long)(b));
    if (a < 0) a = 2.0*pi + a;
    return a;
};

// Calculating the hourangle
//
double f0(double lat, double declin) {
double fo,dfo;
// Correction: different sign at S HS
dfo = rads*(0.5*SunDia + AirRefr); if (lat < 0.0) dfo = -dfo;
fo = tan(declin + dfo) * tan(lat*rads);
if (fo>0.99999) fo=1.0; // to avoid overflow //
fo = asin(fo) + pi/2.0;
return fo;
};

// Calculating the hourangle for twilight times
//
double f1(double lat, double declin) {
double fi,df1;
// Correction: different sign at S HS
df1 = rads * 6.0; if (lat < 0.0) df1 = -df1;
fi = tan(declin + df1) * tan(lat*rads);
if (fi>0.99999) fi=1.0; // to avoid overflow //
fi = asin(fi) + pi/2.0;
return fi;
};


//   Find the ecliptic longitude of the Sun

double FNsun (double d) {

//   mean longitude of the Sun

L = FNrange(280.461 * rads + .9856474 * rads * d);

//   mean anomaly of the Sun

g = FNrange(357.528 * rads + .9856003 * rads * d);

//   Ecliptic longitude of the Sun

return FNrange(L + 1.915 * rads * sin(g) + .02 * rads * sin(2 * g));
};




// Display decimal hours in hours and minutes
// A bit of cheating going on here :)
void showhrmn(double dhr,int *hr,int *mn) 
{
*hr=(int) dhr;
*mn = (dhr - (double) *hr)*60;
};


int sunrise_sunset(int print){ // Print the times of sunrise and sunset if Print is set to TRUE 

double y,m,day,h,latit,longit;
double tzone,d,lambda;
double obliq,alpha,delta,LL,equation,ha,hb,twx;
double twam,altmax,noont,settm,riset,twpm;
time_t sekunnit;
struct tm *p;
time_t current_time;
struct tm *struct_current_time;
static int sunrise_hour = 0;
static int sunrise_minute = 0;
static int sunset_hour = 0;
static int sunset_minute = 0;

int sunrise_minutes = 0;
int sunset_minutes = 0;
int current_minutes = 0;
int sundown = FALSE;


degs = 180.0/pi;
rads = pi/180.0;

/** First get time **/
time(&sekunnit);

/** Next get localtime **/

 p=localtime(&sekunnit);

 y = p->tm_year;
 // this is Y2K compliant method
 y+= 1900;
 m = p->tm_mon + 1;

 day = p->tm_mday;

 h = 12;


 latit = atof(my_lat); 
 longit = atof(my_long);
 tzone = atol(my_tz);
 if(p->tm_isdst !=0){
	 tzone = tzone + 1;
 }

// testing
// m=6; day=10;


d = FNday(y,m,day,h);

//   Use FNsun to find the ecliptic longitude of the
//   Sun

lambda = FNsun(d);

//   Obliquity of the ecliptic

obliq = 23.439 * rads - .0000004 * rads * d;

//   Find the RA and DEC of the Sun

alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
delta = asin(sin(obliq) * sin(lambda));

// Find the Equation of Time
// in minutes
// Correction suggested by David Smith
LL = L - alpha;
if (L < pi) LL += 2.0*pi;
equation = 1440.0 * (1.0 - LL / pi/2.0);
ha = f0(latit,delta);
hb = f1(latit,delta);
twx = hb - ha;	// length of twilight in radians
twx = 12.0*twx/pi;		// length of twilight in hours
/*printf("ha= %.2f   hb= %.2f \n",ha,hb);*/
// Conversion of angle to hours and minutes //
daylen = degs*ha/7.5;
     if (daylen<0.0001) {daylen = 0.0;}
// arctic winter     //

riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
settm = 12.0 + 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
noont = riset + 12.0 * ha/pi;
altmax = 90.0 + delta * degs - latit; 
// Correction for S HS suggested by David Smith
// to express altitude as degrees from the N horizon
if (latit < delta * degs) altmax = 180.0 - altmax;

twam = riset - twx;	// morning twilight begin
twpm = settm + twx;	// evening twilight end

if (riset > 24.0) riset-= 24.0;
if (settm > 24.0) settm-= 24.0;

showhrmn(riset,&sunrise_hour,&sunrise_minute);
sunrise_minutes = (sunrise_hour * 60) + sunrise_minute;
showhrmn(settm,&sunset_hour,&sunset_minute);  
sunset_minutes = (sunset_hour * 60) + sunset_minute;

time(&current_time);
struct_current_time =localtime(&current_time);
current_minutes = (struct_current_time->tm_hour * 60) + struct_current_time->tm_min;
if(current_minutes >= sunset_minutes || current_minutes <= sunrise_minutes)
{
	sundown = TRUE;
}else
{
	sundown = FALSE;
}
if(print){
	print_time();
	fprintf(fpLog,"Sunrise: %02d:%02d  Sunset: %02d:%02d\n",sunrise_hour,sunrise_minute,sunset_hour,sunset_minute);
	fflush(fpLog);
}
return sundown;
}





/*WAITORTIMERCALLBACK */
VOID CALLBACK lpTimeProc(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
	int status = 0;
	char pskill_command[MAX_PATH];
	FILE *pskill_fp;
	char pskill_output[500];

	print_time();
	fprintf(fpLog,"Timer routine called. Sunny Explorer did not stop in time \n");
	fflush(fpLog);
	sprintf(pskill_command,"pskill %s 2>&1",se_executable);
	print_time();
	fprintf(fpLog,"Pskill Command: %s\n",pskill_command);
	fflush(fpLog);
	pskill_fp = _popen(pskill_command,"rt"); 
	if(pskill_fp == NULL)
	{
		print_time();
		fprintf(fpLog,"New Process of PSKILL Failed\n");
		fflush(fpLog);
	} else{
		while (fgets(pskill_output, sizeof(pskill_output), pskill_fp) != NULL)
		{
			print_time();
			fprintf(fpLog,"%s", pskill_output);
			fflush(fpLog);
		}	
		_pclose(pskill_fp);
	}
	g_timer_status = FALSE;
	g_process_killed = TRUE;
}


int generate_se_file(int year,int month,int day,int end_year,int end_month,int end_day)
{
	int status = FALSE;
	
	FILE *se_fp;
	char se_output[500];
	char se_command[500];
			
	char start_date[] = "yyyymmdd";
	char end_date[] = "yyyymmdd";
	char se_input_file[MAX_PATH];
	char se_exec_name[MAX_PATH];
	
	sprintf(start_date,"%d%02d%02d",year,month,day);
	sprintf(end_date,"%d%02d%02d",end_year,end_month,end_day);
	sprintf(se_input_file,"%s\\%s.sx2",se_input_path,plant_name);
	sprintf(se_exec_name,"%s",se_executable);
	sprintf(se_command,"%s \"%s\" -userlevel user -password \"%s\" -exportdir \"%s\" -exportrange \"%s-%s\" -export energy5min 1>&2"
		,se_exec_name,se_input_file,se_password,se_output_path,start_date,end_date);

	print_time();
	fprintf(fpLog,"SE Command: %s\n",se_command);
	fflush(fpLog);
		
	se_fp = _popen(se_command,"rt");
	if (se_fp == NULL){
		print_time();
		fprintf(fpLog,"New Process of SE Failed\n");
		fflush(fpLog);
		return FALSE;
	}
   	while (fgets(se_output, sizeof(se_output), se_fp) != NULL)
	{
		print_time();
		fprintf(fpLog,"%s", se_output);
		fflush(fpLog);
	}		
	status = _pclose(se_fp);  
	status = DeleteTimerQueue(TimerQueue);
	
	if(g_process_killed == TRUE)
	{
		print_time();
		fprintf(fpLog,"generate_se_file reported the g_process_killed flag is TRUE\n");
		fflush(fpLog);
		g_timer_status = FALSE;
	}
	return TRUE;
}



int _tmain(int argc, _TCHAR* argv[])
{
	int loop_count = 0;
	int sundown = FALSE;
	int proc_status = FALSE;
	time_t time_now;
	struct tm *now;
	time_t start_time;
	struct tm *start;
	int in_moon_light = FALSE;
	int start_year = 0;
	int start_month = 0;
	int start_day = 0;

	fpLog = fopen("SE-Download-Log.txt","a+");
	if (fpLog == NULL)
	{
		printf("Cant' Open SE Download Log\n");
		exit(1);
	}
	proc_status = init_params();
	time_out = 60 * 1000 * ((DWORD) atoi(s_time_out)); 

	print_time();
	fprintf(fpLog,"SE Download is Initialized and Running with Timeout: %s Minutes and will Recovery %d CSV files\n",
																	s_time_out,previous_days_to_generate);
	fflush(fpLog);
	sundown = sunrise_sunset(TRUE); // Print the current sunrise and sunset times.
	
	while(1)
	{
		sundown = sunrise_sunset(FALSE);  // Get the state of sunset
		
		if(!sundown)
		{
			if(in_moon_light) // At sunset we went into moon light mode.  At sunrise we come out of moon light mode
			{
				print_time();
				fprintf(fpLog,"Good Morning! We are ready for another DAY!\n");
				sundown = sunrise_sunset(TRUE);
				fflush(fpLog);
				in_moon_light = FALSE;  // Come out of moon light mode
			}
			time_now=time(&time_now);
			now=localtime(&time_now);
			TimerQueue = CreateTimerQueue();
			timer_status = CreateTimerQueueTimer(&phNewTimer,TimerQueue,(WAITORTIMERCALLBACK)lpTimeProc,&Parameter,time_out,0,0);
			if(g_timer_status && (now->tm_min%2 == 0))
			{
				print_time();
				fprintf(fpLog,"MAIN g_timer_status is TRUE\n");
				fflush(fpLog);
				if(g_process_killed)
				{
					print_time();
					fprintf(fpLog,"MAIN g_timer_status is TRUE - g_process_killed Flag is TRUE\n");
					fflush(fpLog);
					g_process_killed = FALSE;
				}
				Sleep(5000);
				if(previous_days_to_generate > 0){
					start_time = time(&start_time);
					start_time = start_time - (previous_days_to_generate * SECONDS_IN_A_DAY);
					start = localtime(&start_time);
					start_year = start->tm_year + 1900;
					start_month = start->tm_mon + 1;
					start_day = start->tm_mday;
					previous_days_to_generate = 0;
				}else{
					start = localtime(&time_now);
					start_year = start->tm_year + 1900;
					start_month = start->tm_mon + 1;
					start_day = start->tm_mday;
				}
				time_now=time(&time_now);
				now=localtime(&time_now);
				proc_status = generate_se_file(start_year,start_month,start_day,
													(now->tm_year + 1900),(now->tm_mon + 1),now->tm_mday);
				if(proc_status == FALSE)
				{
					print_time();
					fprintf(fpLog,"Generate SE File Status Return is %d\n",proc_status);
					fflush(fpLog);
					return FALSE;
				}
			} else {
				if(g_process_killed)
				{
					g_process_killed = FALSE;
				}
				proc_status = DeleteTimerQueue(TimerQueue);
				g_timer_status = TRUE;
			}
		}else{
			if(sundown && !in_moon_light) //If sundown just occured we are not in moon light. Set Moon Light mode.
			{
				print_time();
				fprintf(fpLog,"In Moon Light. SE File Generation Suspended.  See You in the Morning :)\n");
				sundown = sunrise_sunset(TRUE);
				fflush(fpLog);
				in_moon_light = TRUE;  // Set mode to moon light.
			}
		}
		Sleep(5000);
	}
	return TRUE;
}

